package com.gl.portal.system.service;

import java.util.*;
import java.util.stream.Collectors;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TemporalType;
import javax.persistence.criteria.Predicate;

import com.gl.common.util.DateUtils;
import org.hibernate.type.StringType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.gl.common.constant.Constants;
import com.gl.common.enums.DelFlagEnum;
import com.gl.common.exception.CustomException;
import com.gl.common.util.SecurityUtils;
import com.gl.common.util.StringUtils;
import com.gl.framework.security.LoginUser;
import com.gl.framework.web.domain.PageData;
import com.gl.portal.system.entity.SysRole;
import com.gl.portal.system.entity.SysRoleDept;
import com.gl.portal.system.entity.SysRoleMenu;
import com.gl.portal.system.entity.SysUserRole;
import com.gl.portal.system.repository.SysRoleDeptRepository;
import com.gl.portal.system.repository.SysRoleMenuRepository;
import com.gl.portal.system.repository.SysRoleRepository;
import com.gl.portal.system.repository.SysUserRoleRepository;
import com.gl.portal.system.vo.SysRoleVo;
import com.gl.portal.system.vo.SysUserVo;

/**
 * 角色服务实现类
 */
@Service
public class SysRoleService {

    @Autowired
    private SysRoleRepository roleRepository;

    @Autowired
    private SysUserRoleRepository userRoleRepository;

    @Autowired
    private SysRoleMenuRepository roleMenuRepository;

    @Autowired
    private SysRoleDeptRepository roleDeptRepository;

    @Autowired
    private EntityManager em;

    /**
     * 根据条件分页查询角色数据
     *
     * @param filter 过滤条件
     * @return 角色数据集合信息
     */
    public PageData<SysRoleVo> selectRoleList(SysRoleVo filter) {
        PageData<SysRoleVo> pageData = new PageData<>();

        StringBuilder dataSql = new StringBuilder("select r.id, r.role_name as roleName, r.role_key as roleKey, r.sort_num as sortNum, r.remark, " +
                "r.create_user_id as createUserId, u1.user_name as createUserName, r.create_time as createTime, " +
                "r.status\n" +
                "from sys_role r\n" +
                "left join sys_user u1 on r.create_user_id = u1.id\n" +
                "where 1=1");
        StringBuilder countSql = new StringBuilder("SELECT count(1) as total\n" +
                "from sys_role r\n" +
                "left JOIN sys_user u1 ON r.create_user_id = u1.id\n" +
                "where 1=1");


        if (StringUtils.isNotEmpty(filter.getRoleName())) {
            dataSql.append(" and r.role_name like '%" + filter.getRoleName() + "%'");
            countSql.append(" and r.role_name like '%" + filter.getRoleName() + "%'");
        }
        if (StringUtils.isNotEmpty(filter.getRoleKey())) {
            dataSql.append(" and r.role_key like '%" + filter.getRoleKey() + "%'");
            countSql.append(" and r.role_key like '%" + filter.getRoleKey() + "%'");
        }
        if (filter.getStatus() != null) {
            dataSql.append(" and r.status = " + filter.getStatus());
            countSql.append(" and r.status = " + filter.getStatus());
        }
        if (StringUtils.isNotEmpty(filter.getBeginTime()) && StringUtils.isNotEmpty(filter.getEndTime())) {
            dataSql.append(" and DATE_FORMAT(r.create_time,'%Y-%m-%d') >= '"+filter.getBeginTime()+"' and DATE_FORMAT(r.create_time,'%Y-%m-%d') <= '"+filter.getEndTime() +"'");
            countSql.append(" and DATE_FORMAT(r.create_time,'%Y-%m-%d') >= '"+filter.getBeginTime()+"' and DATE_FORMAT(r.create_time,'%Y-%m-%d') <= '"+filter.getEndTime()+"'");
        }
        dataSql.append(" order by sort_num asc");

        String dataSqlStr = dataSql.toString();
        String countSqlStr = countSql.toString();

        //创建本地sql查询实例
        Query dataQuery = em.createNativeQuery(dataSqlStr);
        Query countQuery = em.createNativeQuery(countSqlStr);

        //添加参数
        /*if (StringUtils.isNotEmpty(filter.getRoleName())) {
            dataQuery.setParameter("role_name", "'%" + filter.getRoleName() + "%'");
            countQuery.setParameter("role_name", "'%" + filter.getRoleName() + "%'");
        }
        if (StringUtils.isNotEmpty(filter.getRoleKey())) {
            dataQuery.setParameter("role_key", filter.getRoleKey());
            countQuery.setParameter("role_key", filter.getRoleKey());
        }
        if (filter.getStatus() != null) {
            dataQuery.setParameter("status", filter.getStatus());
            countQuery.setParameter("status", filter.getStatus());
        }
        if (StringUtils.isNotEmpty(filter.getBeginTime()) && StringUtils.isNotEmpty(filter.getEndTime())) {
        	System.out.println(DateUtils.parse(filter.getBeginTime() + " 00:00:00"));
            //dataQuery.setParameter("start_time", DateUtils.parse(filter.getBeginTime() + " 00:00:00"), TemporalType.TIME);
            //countQuery.setParameter("start_time", DateUtils.parse(filter.getBeginTime() + " 00:00:00"), TemporalType.TIME);

            //dataQuery.setParameter("end_time", DateUtils.parse(filter.getEndTime() + " 00:00:00"), TemporalType.TIME);
            //countQuery.setParameter("end_time", DateUtils.parse(filter.getEndTime() + " 00:00:00"), TemporalType.TIME);
        }*/


        //设置分页
        dataQuery.setFirstResult((int) filter.getPageNumber() - 1);
        dataQuery.setMaxResults(filter.getPageSize());

        Long total = Long.parseLong(String.valueOf(countQuery.getSingleResult()));
        List<Object[]> data1 = dataQuery.getResultList();


        List<SysRoleVo> data = new ArrayList<SysRoleVo>();

        for (Object[] obj : data1) {
            SysRoleVo vo = new SysRoleVo();
            vo.setId(Long.parseLong(obj[0].toString()));
            vo.setRoleName(obj[1] != null ? obj[1].toString() : "");
            vo.setRoleKey(obj[2] != null ? obj[2].toString() : "");
            vo.setSortNum(Integer.parseInt(obj[3].toString()));
            vo.setRemark(obj[4] != null ? obj[4].toString() : "");
            vo.setCreateUserId(Long.parseLong(obj[5].toString()));
            vo.setCreateUser(obj[6].toString());
            vo.setCreateTime(DateUtils.parse(obj[7].toString(), "YYYY-mm-dd HH:mm:ss"));
            vo.setStatus(Integer.parseInt(obj[8].toString()));
            data.add(vo);
        }

        List<Long> roleIds = data.stream().map(SysRoleVo::getId).collect(Collectors.toList());
        // 查询角色对应的菜单ID组
        Map<Long, List<Long>> roleIdToMenuIdsMap = roleMenuRepository.findByRoleIdIn(roleIds).stream().collect(Collectors.groupingBy(SysRoleMenu::getRoleId, Collectors.mapping(SysRoleMenu::getMenuId, Collectors.toList())));

        // 查询角色对应的部门ID组
        Map<Long, List<Long>> roleIdToDeptIdsMap = roleDeptRepository.findByRoleIdIn(roleIds).stream().collect(Collectors.groupingBy(SysRoleDept::getRoleId, Collectors.mapping(SysRoleDept::getDeptId, Collectors.toList())));

        data.forEach(vo -> {
            Long id = vo.getId();
            vo.setMenuIds(roleIdToMenuIdsMap.get(id));
            vo.setDeptIds(roleIdToDeptIdsMap.get(id));
        });

        pageData.setTotal(total);
        pageData.setData(data);

        return pageData;
    }

    /**
     * 数据转换
     *
     * @param entity
     * @return
     */
    private SysRoleVo convert(SysRole entity) {
        BeanCopier beanCopier = BeanCopier.create(SysRole.class, SysRoleVo.class, false);
        SysRoleVo vo = new SysRoleVo();
        beanCopier.copy(entity, vo, null);
        return vo;
    }

    /**
     * 根据用户ID查询权限
     *
     * @param userId 用户ID
     * @return 权限列表
     */
    public Set<String> selectRolePermissionByUserId(Long userId) {
        List<Long> roleIdList = userRoleRepository.findByUserId(userId).stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
        if (roleIdList.isEmpty()) {
            return Collections.emptySet();
        }

        List<SysRole> roleList = roleRepository.findByIdInAndIsDeleted(roleIdList, DelFlagEnum.OK.value());
        Set<String> permsSet = new HashSet<>();
        for (SysRole role : roleList) {
            if (StringUtils.isNotNull(role)) {
                permsSet.addAll(Arrays.asList(role.getRoleKey().trim().split(",")));
            }
        }

        return permsSet;
    }

    /**
     * 查询所有角色
     *
     * @return 角色列表
     */
    public List<SysRoleVo> selectRoleAll() {
        return roleRepository.findByIsDeleted(DelFlagEnum.OK.value()).stream().map(this::convert).collect(Collectors.toList());
    }

    /**
     * 根据用户ID获取角色选择框列表
     *
     * @param userId 用户ID
     * @return 选中角色ID列表
     */
    public List<Long> selectRoleListByUserId(Long userId) {
        return userRoleRepository.findByUserId(userId).stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
    }

    /**
     * 通过角色ID查询角色
     *
     * @param roleId 角色ID
     * @return 角色对象信息
     */
    public SysRoleVo selectRoleById(Long roleId) {
        Optional<SysRole> optional = roleRepository.findById(roleId);
        if (!optional.isPresent()) {
            return null;
        }

        SysRole entity = optional.get();
        return this.convert(entity);
    }

    /**
     * 校验角色名称是否唯一
     *
     * @param role 角色信息
     * @return 结果
     */
    public String checkRoleNameUnique(SysRoleVo role) {
        Long roleId = StringUtils.isNull(role.getId()) ? -1L : role.getId();
        SysRole info = roleRepository.findByRoleName(role.getRoleName());
        if (StringUtils.isNotNull(info) && info.getId().longValue() != roleId.longValue()) {
            return Constants.NOT_UNIQUE;
        }
        return Constants.UNIQUE;
    }

    /**
     * 校验角色权限是否唯一
     *
     * @param role 角色信息
     * @return 结果
     */
    public String checkRoleKeyUnique(SysRoleVo role) {
        Long roleId = StringUtils.isNull(role.getId()) ? -1L : role.getId();
        SysRole info = roleRepository.findByRoleKey(role.getRoleKey());
        if (StringUtils.isNotNull(info) && info.getId().longValue() != roleId.longValue()) {
            return Constants.NOT_UNIQUE;
        }
        return Constants.UNIQUE;
    }

    /**
     * 校验角色是否允许操作
     *
     * @param role 角色信息
     */
    public void checkRoleAllowed(SysRoleVo role) {
        if (StringUtils.isNotNull(role.getId()) && role.isAdmin()) {
            throw new CustomException("不允许操作超级管理员角色");
        }
    }

    /**
     * 通过角色ID查询角色使用数量
     *
     * @param roleId 角色ID
     * @return 结果
     */
    public int countUserRoleByRoleId(Long roleId) {
        return userRoleRepository.countByRoleId(roleId);
    }

    public List<SysUserRole> findUserRoleByRoleId(Long roleId) {
        return userRoleRepository.findByRoleId(roleId);
    }

    /**
     * 新增角色信息
     *
     * @param vo 角色信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveRole(SysRoleVo vo) {
        BeanCopier beanCopier = BeanCopier.create(SysRoleVo.class, SysRole.class, false);
        SysRole entity = new SysRole();
        beanCopier.copy(vo, entity, null);

        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUserVo user = loginUser.getUser();
        entity.setIsDeleted(DelFlagEnum.OK.value());
        entity.setCreateUserId(user.getId());
        entity.setCreateTime(new Date());
        // 新增角色信息
        entity = roleRepository.save(entity);

        // 新增角色菜单信息
        this.saveRoleMenu(entity.getId(), vo.getMenuIds());
    }

    /**
     * 修改角色信息
     *
     * @param vo 角色信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateRole(SysRoleVo vo) {
        Optional<SysRole> optional = roleRepository.findById(vo.getId());
        if (!optional.isPresent()) {
            throw new CustomException("角色数据不存在");
        }

        SysRole entity = optional.get();

        BeanCopier beanCopier = BeanCopier.create(SysRoleVo.class, SysRole.class, false);
        beanCopier.copy(vo, entity, null);

        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUserVo user = loginUser.getUser();
        entity.setUpdateUserId(user.getId());
        entity.setUpdateTime(new Date());

        // 修改角色信息
        entity = roleRepository.save(entity);

        // 删除角色与菜单关联
        roleMenuRepository.deleteByRoleId(vo.getId());

        // 新增角色菜单信息
        this.saveRoleMenu(entity.getId(), vo.getMenuIds());
    }

    /**
     * 修改角色状态
     *
     * @param vo 角色信息
     * @return 结果
     */
    public void updateRoleStatus(SysRoleVo vo) {
        Optional<SysRole> optional = roleRepository.findById(vo.getId());
        if (!optional.isPresent()) {
            throw new CustomException("角色数据不存在");
        }

        SysRole entity = optional.get();

        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUserVo user = loginUser.getUser();

        entity.setUpdateUserId(user.getId());
        entity.setUpdateTime(new Date());
        entity.setStatus(vo.getStatus());

        roleRepository.save(entity);
    }

    /**
     * 修改数据权限信息
     *
     * @param vo 角色信息
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    public void authDataScope(SysRoleVo vo) {
        // 删除角色与部门关联
        roleDeptRepository.deleteByRoleId(vo.getId());

        // 新增角色和部门信息（数据权限）
        this.saveRoleDept(vo.getId(), vo.getDeptIds());
    }

    /**
     * 新增角色菜单信息
     *
     * @param roleId  角色Id
     * @param menuIds 菜单ID组
     */
    public void saveRoleMenu(Long roleId, List<Long> menuIds) {
        List<SysRoleMenu> data = menuIds.stream().map(menuId -> {
            SysRoleMenu rm = new SysRoleMenu();
            rm.setRoleId(roleId);
            rm.setMenuId(menuId);
            return rm;
        }).collect(Collectors.toList());

        roleMenuRepository.saveAll(data);
    }

    /**
     * 新增角色部门信息(数据权限)
     *
     * @param roleId  角色ID
     * @param deptIds 部门ID组（数据权限）
     */
    public void saveRoleDept(Long roleId, List<Long> deptIds) {
        List<SysRoleDept> data = deptIds.stream().map(deptId -> {
            SysRoleDept rd = new SysRoleDept();
            rd.setRoleId(roleId);
            rd.setDeptId(deptId);
            return rd;
        }).collect(Collectors.toList());

        roleDeptRepository.saveAll(data);
    }

    /**
     * 通过角色ID删除角色
     *
     * @param roleId 角色ID
     * @return 结果
     */
    public void deleteRoleById(Long roleId) {
        roleRepository.deleteById(roleId);
    }

    /**
     * 批量删除角色信息
     *
     * @param roleIds 需要删除的角色ID
     */
    public void deleteRoleByIds(List<Long> roleIds) {
        for (Long roleId : roleIds) {
            this.checkRoleAllowed(new SysRoleVo(roleId));
            if (this.countUserRoleByRoleId(roleId) > 0) {
                List<SysUserRole> list = this.findUserRoleByRoleId(roleId);
                //删除用户角色关系
                userRoleRepository.deleteAll(list);
                //throw new CustomException(String.format("%1$s已分配,不能删除", role.getRoleName()));
            }
        }

        List<SysRole> entities = roleRepository.findByIdIn(roleIds);
        //改为硬删除
        roleRepository.deleteAll(entities);
//        entities.forEach(entity -> {
//            entity.setIsDeleted(DelFlagEnum.DELETED.value());
//        });
//        roleRepository.saveAll(entities);

        // 删除角色所关联的菜单
        roleMenuRepository.deleteByRoleIdIn(roleIds);
    }

    /**
     * 查询用户部门数据权限列表
     *
     * @param userId 用户ID
     * @return 部门权限列表
     */
    public List<Long> getUserDataScopes(Long userId) {
        List<Long> roleIds = userRoleRepository.findByUserId(userId).stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
        if (roleIds.isEmpty()) {
            return Collections.emptyList();
        }

        return roleDeptRepository.findByRoleIdIn(roleIds).stream().map(SysRoleDept::getDeptId).collect(Collectors.toList());
    }
}
